package com.mebs.edi.scheduler.ftp;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.SocketException;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.log4j.Logger;

/**
 * 
 * This class is used for downloading/uploading files to FTP
 * 
 * @author nit
 * @version 1.0
 * 
 */
public class FtpAccessor {
	
	private static final Logger LOG = Logger.getLogger(FtpAccessor.class);
	
	private String server;
	private String username;
	private String password;
	
	public FtpAccessor(String server, String username, String password) {
		super();
		LOG.debug("Instantiating FtpAccessor");
		this.server = server;
		this.username = username;
		this.password = password;
	}
	
	/**
	 * A simple method testing FTP connection
	 * 
	 * @throws SocketException
	 * @throws IOException
	 */
	public void testConnection() throws SocketException, IOException {
		FTPClient ftp = new FTPClient();
		
		try {
			LOG.debug("Connecting to: " + server + "; using: " + username + "/" + password);
			
			ftp.connect(server);
			ftp.login(username, password);
			
			LOG.debug("Connected to server");
			LOG.debug(ftp.getReplyString());
			
			ftp.logout();
		    ftp.disconnect();
		    
		    LOG.debug("Disconnected from server");
		} catch (IOException e) {
			LOG.error("Cannot connect to FTP", e);
			throw e;
		} 
	}
	
	public List<File> downloadFiles(String folder, String destinationFolder, boolean deleteAfterDownload) 
		throws SocketException, IOException {
		return downloadFiles(folder, destinationFolder, deleteAfterDownload, null, null);
	}
	
	public List<File> downloadFiles(String folder, String destinationFolder, boolean deleteAfterDownload, Calendar start) 
			throws SocketException, IOException {
		return downloadFiles(folder, destinationFolder, deleteAfterDownload, start, null);
	}
	
	/**
	 * Download files from FTP to the specified destination folder
	 * 
	 * @param folder - FTP folder, containing the files
	 * @param destinationFolder
	 * @param moveToAfterDownload - after downloading the files will be moved to this dir on FTP
	 * @param start - only files newer than this date will be downloaded
	 * @param end - only files older than this date will be downloaded
	 * 
	 * @throws SocketException
	 * @throws IOException
	 */
	public List<File> downloadFiles(String folder, String destinationFolder, boolean deleteAfterDownload, 
			Calendar start, Calendar end) throws SocketException, IOException {
		List<File> downloadedFiles = new ArrayList<File>();
		FTPClient ftp = new FTPClient();
		
		try {
			ftp.connect(server);
			ftp.login(username, password);
			
			LOG.debug("Connected to server!");
			LOG.debug(ftp.getReplyString());
			
			// List the files in the directory
		    ftp.changeWorkingDirectory(folder);
		    LOG.debug("Changed working directory to: " + folder);
		    FTPFile[] files = ftp.listFiles();
		    
		    LOG.debug( "Number of files in dir: " + files.length );
		    
		    DateFormat df = DateFormat.getDateInstance( DateFormat.SHORT );
		    for (FTPFile f : files) {
		    	LOG.debug("Processing " + f.getName());
		    	Date fileDate = f.getTimestamp().getTime();
		    	
		    	// skipping older files
		    	if (start != null && fileDate.compareTo(start.getTime()) < 0) {
		    		continue;
		    	}
		    	// skipping newer files
		    	if (end != null && fileDate.compareTo(end.getTime()) > 0) {
		    		continue;
		    	}
		    	
		    	LOG.debug("Downloading " + f.getName() + "\t" + df.format(fileDate));
		    	File downloaded = new File(destinationFolder + File.separator + f.getName());
		    	FileOutputStream fos = new FileOutputStream(downloaded);
		    	
		    	ftp.retrieveFile(f.getName(), fos);
		    	fos.close();
		    	downloaded.setLastModified(fileDate.getTime());
		    	
		    	if (deleteAfterDownload) {
		    		LOG.debug("Deleting " + f.getName() + "\t" + df.format(fileDate));
		    		ftp.deleteFile(f.getName());
		    	}
		    	
		    	downloadedFiles.add(downloaded);
		    }
			
			ftp.logout();
		    ftp.disconnect();
		    
		    LOG.debug("Disconnected from server");
		    
		    return downloadedFiles;
		    
		} catch (Throwable e) {
			LOG.debug("Error downloading files from FTP", e);
			throw new IOException(e);
		} 
	}
	
	/**
	 * Uploads a file to FTP
	 * 
	 * @param file
	 * @param ftpFolder
	 * 
	 * @throws SocketException
	 * @throws IOException
	 */
	public void uploadFile(File file, String ftpFolder) throws SocketException, IOException {
		FTPClient ftp = new FTPClient();
		
		try {
			ftp.connect(server);
			ftp.login(username, password);
			
			LOG.debug("Connected to server");
			LOG.debug(ftp.getReplyString());
			
			// List the files in the directory
		    ftp.changeWorkingDirectory(ftpFolder);
		    
		    LOG.debug("Uploading " + file.getName() + " to " + ftpFolder);
		    FileInputStream fis = new FileInputStream(file);
		    
		    ftp.storeFile(file.getName(), fis);
		    fis.close();

			ftp.logout();
		    ftp.disconnect();
		    
		    LOG.debug("Disconnected from server");
		} catch (IOException e) {
			LOG.error("Error uploading " + file + " to FTP", e);
			throw e;
		} 
	}

	public String getServer() {
		return server;
	}

	public void setServer(String server) {
		this.server = server;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}
	
}
